﻿using System;
using System.Collections.Generic;
using System.Text;

namespace MatchCore
{
    public class LogicManager
    {
        private List<Player> _players = new List<Player>();
        private List<Bullet> _bullets = new List<Bullet>();

        private uint _curFrameId = 0;

        private bool _started = false;

        private Rect _sceneRect;

        private IGameEventer _gameEventer;

        private ILoger _loger;

        public LogicManager()
        {

        }

        public void SetSceneRect(Rect sceneRect)
        {
            _sceneRect = sceneRect;
        }

        public Rect GetSceneRect()
        {
            return _sceneRect;
        }

        public void SetGameEventer(IGameEventer gameEventer)
        {
            _gameEventer = gameEventer;
        }

        public void SetLoger(ILoger loger)
        {
            _loger = loger;
        }

        public void LogError(string text)
        {
            if(_loger != null)
            {
                _loger.LogError(text);
            }
        }

        public void LogDebug(string text)
        {
            if (_loger != null)
            {
                _loger.LogDebug(text);
            }
        }

        public void LogException(string text)
        {
            if (_loger != null)
            {
                _loger.LogException(text);
            }
        }

        static private LogicManager sLogicManager = null;
        public static LogicManager Instance()
        {
            if(null == sLogicManager)
            {
                sLogicManager = new LogicManager();
            }
            return sLogicManager;
        }

        public static void Destroy()
        {
            sLogicManager = null;
        }

        public uint GetCurFrameId()
        {
            return _curFrameId;
        }

        public void AddPlayer(Player player)
        {
            _players.Add(player);
        }

        public Player FindPlayerByIndex(uint index)
        {
            foreach(var player in _players)
            {
                if(player.GetIndex() == index)
                {
                    return player;
                }
            }
            return null;
        }

        public void AddBullet(Bullet bullet)
        {
            _bullets.Add(bullet);
        }

        public bool RemoveBullet(Bullet bullet)
        {
            for(int i = 0; i < _bullets.Count; i++)
            {
                if(_bullets[i].Equals(bullet))
                {
                    _bullets.RemoveAt(i);
                    return true;
                }
            }
            return false;
        }

        public bool Start()
        {
            if(_started)
            {
                return false;
            }    

            _started = true;

            return true;
        }

        public bool Stop()
        {
            if (!_started)
            {
                return false;
            }

            _started = false;

            return true;
        }

        public bool OnUpdateFrame(Frame frame)
        {
            if (!_started)
            {
                return false;
            }

            if(!(_curFrameId + 1 == frame.frameId))
            {
                return false;
            }

            _curFrameId = frame.frameId;

            if(Config.GAME_PREPARE_FRAME_ID == _curFrameId)
            {
                if(_gameEventer != null)
                {
                    _gameEventer.OnGameStarted();
                }
            }

            if(_curFrameId >= Config.GAME_PREPARE_FRAME_ID)
            {
                foreach (var playerFrame in frame.datas)
                {
                    var player = FindPlayerByIndex(playerFrame.index);
                    if (null == player)
                    {
                        continue;
                    }

                    CommandType cmd = Command.ParseCommandType(playerFrame.cmd);
                    switch (cmd)
                    {
                        case CommandType.Move:
                            {
                                MoveDirType dir = Command.ParseMoveDirType(playerFrame.cmd);
                                Vector2 dirValue = new Vector2();
                                switch (dir)
                                {
                                    case MoveDirType.Up:
                                        dirValue.y = -1;
                                        break;
                                    case MoveDirType.Down:
                                        dirValue.y = 1;
                                        break;
                                }
                                OnPlayerMove(player, dirValue);
                            }
                            break;
                        case CommandType.Shoot:
                            {
                                OnPlayerShoot(player);
                            }
                            break;
                    }
                }

                UpdateLogic(_curFrameId);
            }

            return true;
        }

        private void UpdateLogic(uint frameId)
        {
            foreach (var player in _players)
            {
                player.Update(frameId);
            }

            foreach (var buttle in _bullets)
            {
                buttle.Update(frameId);
            }

            bool gameOver = false;

            for(int i = 0; i < _bullets.Count;)
            {
                bool hited = false;

                var buttle = _bullets[i];
                Player beShootPlayer = null;

                foreach (var player in _players)
                {
                    if(buttle.HitTest(player))
                    {
                        player.OnBeShoot(buttle);
                        beShootPlayer = player;

                        hited = true;

                        if(player.GetBlood() <= 0)
                        {
                            gameOver = true;
                        }

                        break;
                    }
                }

                if(hited)
                {
                    _bullets.RemoveAt(i);

                    buttle.OnHitPlayer(beShootPlayer);
                }
                else
                {
                    if(!_sceneRect.Contains(buttle.GetPosition()))
                    {
                        _bullets.RemoveAt(i);

                        buttle.OnDestroy();
                    }
                    else
                    {
                        i++;
                    }
                }

                if(gameOver)
                {
                    break;
                }
            }

            if(gameOver)
            {
                _started = false;

                if (_gameEventer != null)
                {
                    try
                    {
                        _gameEventer.OnGameOver();
                    }
                    catch(Exception ex)
                    {
                        LogException("call OnGameOver ex:" + ex);
                    }
                }
            }
        }

        private void OnPlayerMove(Player player,Vector2 dir)
        {
            player.OnMove(dir);
        }

        private void OnPlayerShoot(Player player)
        {
            var bullet = new Bullet(player, player.GetShootDir() * Config.BULLET_NORMAL_SPEED,Config.BULLET_DEFAULT_DAMAGE);
            AddBullet(bullet);

            player.OnShoot(bullet);
        }
    }
}
